package com.fire.activiti.activitidb.process.impl;


import com.fire.activiti.activitidb.process.ProcessEngine;
import com.fire.activiti.activitidb.process.adapter.ActivitiEngineConfigurationConfigurer;
import com.fire.activiti.activitidb.process.adapter.ProcessConfig;
import com.fire.activiti.activitidb.process.util.DataBaseUtil;
import org.activiti.spring.ProcessEngineFactoryBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.sql.Connection;
import java.util.Objects;

/**
 * @author Mr.Fire
 * @date 2021/12/21
 * @desc 引擎提供器
 */
@Component
public class ProcessEngineBuilder implements ApplicationContextAware, DisposableBean {

    @Autowired
    private PlatformTransactionManager transactionManager;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private ActivitiEngineConfigurationConfigurer activitiEngineConfigurationConfigurer;

    private Activiti6ProcessEngine processEngine;

    private ApplicationContext applicationContext;


    /**
     * 获取流程引擎
     * @return
     */
    public ProcessEngine build(){
        if (Objects.nonNull(processEngine)){
            return processEngine;
        }
        synchronized (this){
            processEngine =  buildProcessEngine();
        }
        return processEngine;
    }

    private Activiti6ProcessEngine buildProcessEngine() {
        try {
            ProcessEngineFactoryBean engineFactory = new ProcessEngineFactoryBean();
            engineFactory.setApplicationContext(applicationContext);
            ProcessConfig processConfig = new ProcessConfig();
            engineFactory.setProcessEngineConfiguration(processConfig);
            buildDataSource(processConfig);
            //判断原生activiti是否支持应用数据库
            String dbType = getDataBaseType();
            if(null!=dbType){
                //设置数据库类型
                processConfig.setDatabaseType(dbType);
                activitiEngineConfigurationConfigurer.configure(processConfig);
            }
            return new Activiti6ProcessEngine(engineFactory.getObject());
        } catch (Exception e) {
            throw new RuntimeException("构建流程引擎错误");
        }
    }

    private  String getDataBaseType() {
        DataSource dataSource = jdbcTemplate.getDataSource();
        Connection conn=null;
        try {
            conn= DataSourceUtils.getConnection(dataSource);
            return DataBaseUtil.getDatabaseType(conn);
        }finally {
            DataSourceUtils.releaseConnection(conn,dataSource);
        }
    }


    private void buildDataSource(ProcessConfig cfg){
        // 获取数据源
        DataSource dataSource = jdbcTemplate.getDataSource();
        cfg.setDataSource(dataSource);
        //设置数据库事务
        cfg.setTransactionManager(transactionManager);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void destroy() throws Exception {
        if (processEngine!=null){
            processEngine.destory();
        }
    }
}


